package com.tbit.uqbike.service.business.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.tbit.uqbike.constant.enums.AccountDayStatEnum;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.Account;
import com.tbit.uqbike.object.pojo.AccountDayStat;
import com.tbit.uqbike.object.pojo.vo.HasOrderMachineVO;
import com.tbit.uqbike.object.pojo.vo.OperationReportVO;
import com.tbit.uqbike.service.business.OperationReportService;
import com.tbit.uqbike.webmanager.dao.core.AccountDao;
import com.tbit.uqbike.webmanager.dao.stat.AccountDayStatDao;
import com.tbit.uqbike.webmanager.dao.stat.MachineOperationsStatDao;
import com.tbit.uqbike.webmanager.util.StringUtils;
import com.tbit.utils.DateTimeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author:BUGTian
 * @DATE: 2022/11/11
 */
@Service
public class OperationReportServiceImpl implements OperationReportService {

    private static final String SPIT = "_";
    private static final int SUM = 0;
    private static final int CNT = 1;
    @Autowired
    private AccountDayStatDao accountDayStatDao;
    @Resource
    private MachineOperationsStatDao machineOperationsStatDao;
    @Autowired
    private AccountDao accountDao;

    @Override
    public List<OperationReportVO> groupByArea(String adAccountIds, Date startTime, Date endTime) {
        if (StringUtils.isEmpty(adAccountIds)) {
            return Collections.emptyList();
        }
        List<Integer> accountIds = Stream.of(adAccountIds.split(",")).map(Integer::parseInt).collect(Collectors.toList());
        List<Account> accountList = accountDao.getByAccountIds(accountIds);
        if (CollectionUtil.isEmpty(accountList)) {
            throw new BaseException("请选择区域");
        }
        Integer parseEndTime = DateTimeUtil.parseDataDate(endTime);
        //汇总数据
        Map<String, AccountDayStat> sumStatMap = accountDayStatDao.sum(accountIds, AccountDayStatEnum.getOperationSumType(), DateTimeUtil.parseDataDate(startTime), parseEndTime);
        //当天数据
        Map<String, AccountDayStat> endTimeStatMap = accountDayStatDao.sum(accountIds, AccountDayStatEnum.getOperationType(), parseEndTime, parseEndTime);

        //当天产生订单车辆数
        List<HasOrderMachineVO> hasOrderMachineVOS = machineOperationsStatDao.selectMachineOrderCount(accountIds, startTime, endTime);
        Map<Integer, Integer> hasOrderMachineCountMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(hasOrderMachineVOS)){
            hasOrderMachineCountMap = hasOrderMachineVOS.stream()
                    .filter(Objects::nonNull)
                    .filter(vo -> vo.getAccountId() != null)
                    .collect(Collectors.toMap(HasOrderMachineVO::getAccountId, HasOrderMachineVO::getOrderCarCount));
        }
        long dayAvg = DateUtil.betweenDay(startTime, endTime, true) + 1;

        Map<Integer, Integer> finalHasOrderMachineCountMap = hasOrderMachineCountMap;
        return accountList.stream()
                .map(account -> getOperationReportVO(sumStatMap, endTimeStatMap, finalHasOrderMachineCountMap, account.getAccountId().toString())
                        .setAreaName(account.getName())
                        .setAccountId(account.getAccountId()))
                .peek(x -> {
                    x.setVehicleAverageMoney(String.format("%.2f", NumberUtil.div(Double.parseDouble(x.getVehicleAverageMoney()), dayAvg, 2)));
                    x.setVehicleAverageOrder(String.format("%.2f", NumberUtil.div(Double.parseDouble(x.getVehicleAverageOrder()), dayAvg, 2)));
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<OperationReportVO> groupByDay(Integer adAccountId, Date startTime, Date endTime) {
        List<OperationReportVO> list = new ArrayList<>();
        List<String> betweenEveryDay = DateTimeUtil.getBetweenEveryDay(startTime, endTime);
        // 定义日期格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        // 使用 Lambda 表达式进行倒序排序
        Collections.sort(betweenEveryDay, (o1, o2) -> {
            LocalDate date1 = LocalDate.parse(o1, formatter);
            LocalDate date2 = LocalDate.parse(o2, formatter);
            return date2.compareTo(date1); // 倒序
        });
        Integer parseEndTime = DateTimeUtil.parseDataDate(endTime);
        List<Integer> operationSumType = AccountDayStatEnum.getOperationSumType();
        operationSumType.addAll(AccountDayStatEnum.getOperationType());
        Map<String, AccountDayStat> statMap = accountDayStatDao.sumGroupByDay(adAccountId, operationSumType, DateTimeUtil.parseDataDate(startTime), parseEndTime);
        //当天产生订单车辆数
        List<HasOrderMachineVO> hasOrderMachineVOS = machineOperationsStatDao.selectMachineOrderCountByDay(adAccountId, startTime, endTime);
        Map<Integer, Integer> hasOrderMachineCountMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(hasOrderMachineVOS)){
            hasOrderMachineCountMap = hasOrderMachineVOS.stream().collect(Collectors.toMap(HasOrderMachineVO::getFlag, HasOrderMachineVO::getOrderCarCount));
        }
        Account account = accountDao.getByAccountId(adAccountId);
        if (account == null) {
            throw new BaseException("请选择区域");
        }
        for (String s : betweenEveryDay) {
            list.add(getOperationReportVO(statMap, statMap, hasOrderMachineCountMap, s.replace("-", ""))
                    .setAreaName(account.getName())
                    .setDay(s)
                    .setAccountId(adAccountId));
        }
        return list;
    }

    /**
     * 计算返回数据
     *
     * @param sumStatMap     汇总数据
     * @param endTimeStatMap 当天数据
     * @param prefix         key前缀
     * @return
     */
    public OperationReportVO getOperationReportVO(Map<String, AccountDayStat> sumStatMap, Map<String, AccountDayStat> endTimeStatMap, Map<Integer, Integer> hasOrderMachineCountMap, String prefix) {
        OperationReportVO operationReportVO = new OperationReportVO();
        operationReportVO.setVehicleTotal(getValue(endTimeStatMap, prefix + SPIT + AccountDayStatEnum.TOTAL_NUMBER_OF_VEHICLES.getDataType(), CNT))
                .setPunInVehicleTotal(getValue(endTimeStatMap, prefix + SPIT + AccountDayStatEnum.NUMBER_OF_VEHICLES_LAUNCHED.getDataType(), CNT))
                .setOperationVehicleTotal(getValue(endTimeStatMap, prefix + SPIT + AccountDayStatEnum.NUMBER_OF_OPERATIONAL_VEHICLES.getDataType(), CNT))
                .setVehicleAverageOrder(String.format("%.2f", NumberUtil.div(getValue(sumStatMap, prefix + SPIT + AccountDayStatEnum.NUMBER_OF_ORDERS_PER_VEHICLE.getDataType(), CNT).doubleValue(), 100D, 2)))
                .setChargingTotal(getValue(sumStatMap, prefix + SPIT + AccountDayStatEnum.NUMBER_OF_POWER_CHANGES.getDataType(), SUM))
                .setMoveTotal(getValue(sumStatMap, prefix + SPIT + AccountDayStatEnum.NUMBER_OF_MOVES.getDataType(), SUM))
                .setDispatchTotal(getValue(sumStatMap, prefix + SPIT + AccountDayStatEnum.NUMBER_OF_DISPATCHES.getDataType(), SUM))
                .setUserTotal(getValue(endTimeStatMap, prefix + SPIT + AccountDayStatEnum.CUMULATIVE_NUMBER_OF_USERS.getDataType(), CNT))
                .setNewUserTotal(getValue(sumStatMap, prefix + SPIT + AccountDayStatEnum.NUMBER_OF_NEW_USERS.getDataType(), CNT))
                .setHasOrderMachineCount(hasOrderMachineCountMap.getOrDefault(Integer.parseInt(prefix), 0).longValue());
        operationReportVO.compute();
        //车均订单收入 单独计算
        operationReportVO.setVehicleAverageMoney(String.format("%.2f", NumberUtil.div(getValue(sumStatMap, prefix + SPIT + AccountDayStatEnum.AVERAGE_VEHICLE_INCOME.getDataType(), SUM).doubleValue(), 100D, 2)));
        return operationReportVO;
    }

    /**
     * 获取值
     *
     * @param map  数据
     * @param flag 取值的key
     * @param type 0:金额, 1:数量
     * @return
     */
    public Long getValue(Map<String, AccountDayStat> map, String flag, Integer type) {
        AccountDayStat accountDayStat = map.get(flag);
        return accountDayStat == null ? 0L : type == 0 ? accountDayStat.getSumTotal() : accountDayStat.getCntTotal();
    }


}
